package fr.vahren.sriksal.generation;

import java.io.IOException;

import org.j3d.texture.procedural.PerlinNoiseGenerator;

import fr.vahren.sriksal.generation.Eroder.BiomeGeneationMode;
import fr.vahren.sriksal.generation.Eroder.RainGenerationMode;
import fr.vahren.sriksal.generation.Eroder.StrategyMode;

public class Generator {

	public static final int ALTITUDE_RESOLUTION = 255;
	public static final int WIDTH = 500;
	public static final int HEIGHT = 500;
	private static final int TEMPEATURE_RESOLUTION = 5;
	private static final int HUMIDITY_RESOLUTION = 5;

	private Eroder eroder;

	public Generator() {
		eroder = new Eroder(StrategyMode.RIVER,
				RainGenerationMode.RIVERSPAWNER, BiomeGeneationMode.DEFAULT);

	}

	public void erode() {
		eroder.erode(HEIGHT, WIDTH);
	}

	public void generateRivers() {
		eroder.generateRivers();
	}

	public void generateBiomes() {
		eroder.generateBiomes();
	}

	public void exportMaps(String fileName) {
		DrawingUtils.getInstance().exportAll(eroder.getMap("water"),
				eroder.getMap("height"), eroder.getMap("terrain"),
				eroder.getMap("biome"), fileName);
	}

	public static void main(String[] args) throws IOException {
		Generator generator = new Generator();

		generator.erode();
		generator.generateRivers();
		generator.generateBiomes();
		generator.exportMaps("images/map1.bmp");
	}

	public static int[][] generateHeightMap(int height, int width,
			int noiseFactor, int turbFactor) {
		int normalizationFactor = ALTITUDE_RESOLUTION;

		int[][] normalizedMap = generateNormalizedMap(height, width,
				noiseFactor, turbFactor, normalizationFactor);
		return normalizedMap;
	}

	private static int[][] generateNormalizedMap(int height, int width,
			int noiseFactor, int turbFactor, int normalizationFactor) {
		float[][] map = new float[height][width];

		// generate the map from perlin noise.
		PerlinNoiseGenerator generator = new PerlinNoiseGenerator(
				(int) System.currentTimeMillis());

		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				map[i][j] = generator.noise2(i / (float) height * noiseFactor,
						j / (float) width * noiseFactor);
				map[i][j] += generator.turbulence2(i / (float) height
						* turbFactor, j / (float) width * turbFactor, 0.5f);
			}
		}
		// Normalize
		float min = 10;
		float max = -10;
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				float m = map[i][j];
				if (m < min) {
					min = m;
				}
				if (m > max) {
					max = m;
				}
			}
		}

		int[][] normalizedMap = new int[height][width];
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				normalizedMap[i][j] = (int) ((map[i][j] - min) / (max - min) * normalizationFactor);
			}
		}
		return normalizedMap;
	}

	public static double[][] generateDensityMap(int height, int width,
			int noiseFactor, int turbFactor) {
		float[][] map = new float[height][width];

		// generate the map from perlin noise.
		PerlinNoiseGenerator generator = new PerlinNoiseGenerator(
				(int) System.currentTimeMillis());

		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				map[i][j] = generator.noise2(i / (float) height * noiseFactor,
						j / (float) width * noiseFactor);
				map[i][j] += generator.turbulence2(i / (float) height
						* turbFactor, j / (float) width * turbFactor, 0.5f);
			}
		}
		// Normalize
		float min = 10;
		float max = -10;
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				float m = map[i][j];
				if (m < min) {
					min = m;
				}
				if (m > max) {
					max = m;
				}
			}
		}

		double[][] normalizedMap = new double[height][width];
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				normalizedMap[i][j] = ((map[i][j] - min) / (max - min));
			}
		}
		return normalizedMap;
	}

	public static int[][] generateMaterialMap(int height, int width, int depht) {
		int[][] map = new int[height][width];
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				map[i][j] = depht;
			}
		}
		return map;
	}

	public static int[][] generateTemperatureMap(int height, int width,
			int turbFactor, int noiseFactor) {
		int normalizationFactor = TEMPEATURE_RESOLUTION;

		int[][] normalizedMap = generateNormalizedMap(height, width,
				noiseFactor, turbFactor, normalizationFactor);
		return normalizedMap;
	}

	public static int[][] generateHumidityMap(int height, int width,
			int noiseFactor, int turbFactor) {
		int normalizationFactor = HUMIDITY_RESOLUTION;

		int[][] normalizedMap = generateNormalizedMap(height, width,
				noiseFactor, turbFactor, normalizationFactor);
		return normalizedMap;
	}

}
